﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Diagnostics;
using System.Windows;
using Xceed.Silverlight.ListBox.Utils;
using Xceed.Silverlight.Utils;
using Xceed.Silverlight.DragDrop;

namespace Xceed.Silverlight.ListBox
{
  public abstract class ContainerConfigurationsBase : DependencyObject, IWeakEventListener
  {
    #region CONSTRUCTORS

    private static ListBoxItemConfiguration DefaultListBoxItemConfiguration;
    private static ListBoxGroupHeaderConfiguration DefaultListBoxGroupHeaderConfiguration;

    static ContainerConfigurationsBase()
    {
      ContainerConfigurationsBase.DefaultListBoxItemConfiguration = new ListBoxItemConfiguration();
      ContainerConfigurationsBase.DefaultListBoxGroupHeaderConfiguration = new ListBoxGroupHeaderConfiguration();

      Debug.Assert( ( ContainerConfigurationsBase.DefaultListBoxItemConfiguration.ContentTemplate == null ) && ( ContainerConfigurationsBase.DefaultListBoxItemConfiguration.ContainerStyle == null ) );
      Debug.Assert( ( ContainerConfigurationsBase.DefaultListBoxGroupHeaderConfiguration.ContentTemplate == null ) && ( ContainerConfigurationsBase.DefaultListBoxGroupHeaderConfiguration.ContainerStyle == null ) );
    }

    public ContainerConfigurationsBase()
    {
      // Always instanciate a DraggedContainerConfiguration as default value.
      // We don't want to affect the DP default value to avoid a static reference
      // shared by more than one ContainerConfigurations
      this.DraggedElementConfiguration = new DraggedElementConfiguration();
    }

    #endregion CONSTRUCTORS

    #region DraggedContainerConfiguration Property

    public static readonly DependencyProperty DraggedElementConfigurationProperty = DependencyProperty.Register(
      "DraggedElementConfiguration",
      typeof( DraggedElementConfiguration ),
      typeof( ContainerConfigurationsBase ),
      new PropertyMetadata(
        null,
        new PropertyChangedCallback( ContainerConfigurationsBase.OnDraggedElementConfigurationChanged ) ) );

    public DraggedElementConfiguration DraggedElementConfiguration
    {
      get
      {
        return ( DraggedElementConfiguration )this.GetValue( ContainerConfigurationsBase.DraggedElementConfigurationProperty );
      }
      set
      {
        this.SetValue( ContainerConfigurationsBase.DraggedElementConfigurationProperty, value );
      }
    }

    private static void OnDraggedElementConfigurationChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      ContainerConfigurationsBase containerConfiguration = ( ContainerConfigurationsBase )sender;

      DraggedElementConfiguration oldDraggedElementConfiguration = e.OldValue as DraggedElementConfiguration;
      DraggedElementConfiguration newDraggedElementConfiguration = e.NewValue as DraggedElementConfiguration;

      containerConfiguration.Invalidate();
    }

    #endregion

    #region ListBoxItemConfiguration Property

    public static readonly DependencyProperty ListBoxItemConfigurationProperty = DependencyProperty.Register(
       "ListBoxItemConfiguration",
       typeof( ListBoxItemConfiguration ),
       typeof( ContainerConfigurationsBase ),
       new PropertyMetadata( null, ContainerConfigurationsBase.OnListBoxItemConfigurationChanged ) );

    public ListBoxItemConfiguration ListBoxItemConfiguration
    {
      get
      {
        return ( ListBoxItemConfiguration )this.GetValue( ContainerConfigurationsBase.ListBoxItemConfigurationProperty );
      }
      set
      {
        this.SetValue( ContainerConfigurationsBase.ListBoxItemConfigurationProperty, value );
      }
    }

    private static void OnListBoxItemConfigurationChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      ContainerConfigurationsBase containerConfiguration = ( ContainerConfigurationsBase )sender;

      ListBoxItemConfiguration oldListBoxItemConfiguration = e.OldValue as ListBoxItemConfiguration;
      ListBoxItemConfiguration newListBoxItemConfiguration = e.NewValue as ListBoxItemConfiguration;

      if( oldListBoxItemConfiguration != null )
      {
        ContentTemplateChangedManager.RemoveListener( oldListBoxItemConfiguration, containerConfiguration );
        ItemContainerStyleChangedManager.RemoveListener( oldListBoxItemConfiguration, containerConfiguration );
      }

      if( newListBoxItemConfiguration != null )
      {
        ContentTemplateChangedManager.AddListener( newListBoxItemConfiguration, containerConfiguration );
        ItemContainerStyleChangedManager.AddListener( newListBoxItemConfiguration, containerConfiguration );
      }

      containerConfiguration.Invalidate();
    }

    #endregion ItemConfiguration Property

    #region ListBoxGroupHeaderConfiguration Property

    public static readonly DependencyProperty ListBoxGroupHeaderConfigurationProperty = DependencyProperty.Register(
       "ListBoxGroupHeaderConfiguration",
       typeof( ListBoxGroupHeaderConfiguration ),
       typeof( ContainerConfigurationsBase ),
       new PropertyMetadata( null, ContainerConfigurationsBase.OnListBoxGroupHeaderConfigurationChanged ) );

    public ListBoxGroupHeaderConfiguration ListBoxGroupHeaderConfiguration
    {
      get
      {
        return ( ListBoxGroupHeaderConfiguration )this.GetValue( ContainerConfigurationsBase.ListBoxGroupHeaderConfigurationProperty );
      }
      set
      {
        this.SetValue( ContainerConfigurationsBase.ListBoxGroupHeaderConfigurationProperty, value );
      }
    }

    private static void OnListBoxGroupHeaderConfigurationChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e )
    {
      ContainerConfigurationsBase containerConfigurations = ( ContainerConfigurationsBase )sender;

      ListBoxGroupHeaderConfiguration oldListBoxGroupHeaderConfiguration = e.OldValue as ListBoxGroupHeaderConfiguration;
      ListBoxGroupHeaderConfiguration newListBoxGroupHeaderConfiguration = e.NewValue as ListBoxGroupHeaderConfiguration;

      if( oldListBoxGroupHeaderConfiguration != null )
      {
        ContentTemplateChangedManager.RemoveListener( oldListBoxGroupHeaderConfiguration, containerConfigurations );
        ItemContainerStyleChangedManager.RemoveListener( oldListBoxGroupHeaderConfiguration, containerConfigurations );
      }

      if( newListBoxGroupHeaderConfiguration != null )
      {
        ContentTemplateChangedManager.AddListener( newListBoxGroupHeaderConfiguration, containerConfigurations );
        ItemContainerStyleChangedManager.AddListener( newListBoxGroupHeaderConfiguration, containerConfigurations );
      }

      containerConfigurations.Invalidate();
    }

    #endregion ListBoxGroupHeaderConfiguration Property

    #region Public Methods

    public void Invalidate()
    {
      // Invalidate everything.
      this.Invalidate( ConfigurationType.All );
    }

    #endregion Public Methods

    #region Internal Methods

    internal void Invalidate( ConfigurationType configurationType )
    {
      if( this.ContainerConfigurationsInvalidated != null )
      {
        this.ContainerConfigurationsInvalidated( this, new ConfigurationChangedEventArgs( configurationType ) );
      }
    }

    internal ListBoxContainerConfigurationBase GetContainerConfiguration( ConfigurationType configurationType )
    {
      if( configurationType == ConfigurationType.All )
        throw new ArgumentException( "Any not a valid ConfigurationType value", "configurationType" );
      ListBoxContainerConfigurationBase containerConfiguration = this.GetContainerConfigurationCore( configurationType );

      // We never want to return a null configuration as there must always be an
      // active configuration for a given container type.
      // Use the default configurations instead.
      if( containerConfiguration == null )
      {
        if( configurationType == ConfigurationType.Item )
        {
          containerConfiguration = ContainerConfigurationsBase.DefaultListBoxItemConfiguration;
        }
        else if( configurationType == ConfigurationType.GroupHeader )
        {
          containerConfiguration = ContainerConfigurationsBase.DefaultListBoxGroupHeaderConfiguration;
        }
      }

      return containerConfiguration;
    }

    internal ListBoxContainerConfigurationBase GetContainerConfigurationCore( ConfigurationType configurationType )
    {
      ListBoxContainerConfigurationBase containerConfiguration = null;

      if( configurationType == ConfigurationType.Item )
      {
        containerConfiguration = this.ListBoxItemConfiguration;
      }
      else if( configurationType == ConfigurationType.GroupHeader )
      {
        containerConfiguration = this.ListBoxGroupHeaderConfiguration;
      }
      else
      {
        throw new InvalidOperationException(
          "An error occured trying to fetch a ListBoxContainerConfigurationBase instance for the specified configuration type " + configurationType + "." );
      }

      return containerConfiguration;
    }

    #endregion Internal Methods


    #region ContainerConfigurationsInvalidated Event

    internal event EventHandler<ConfigurationChangedEventArgs> ContainerConfigurationsInvalidated;

    #endregion ContainerConfigurationsInvalidated Event

    #region IWeakEventListener Members

    bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e )
    {
      bool handled = false;

      if( ( managerType == typeof( ContentTemplateChangedManager ) )
        || ( managerType == typeof( ItemContainerStyleChangedManager ) ) )
      {
        handled = true;

        ListBoxContainerConfigurationBase configuration = ( ListBoxContainerConfigurationBase )sender;
        this.Invalidate( configuration.ConfigurationType );
      }

      return handled;
    }

    #endregion
  }
}
